package threadpool

import (
	"dev_gw/queue"
	"reflect"
	"sync"
)

type fn struct {
	callback interface{}
	args     []reflect.Value
}

type ThreadPool struct {
	tasks       *queue.Queue[fn]
	cond        *sync.Cond
	mu          sync.Mutex
	workerCount int
	stop        bool
}

// type Task[T any] func(...T)

// func wrapFunction[T any](fn Task[T], args ...T) func() {
// 	return func() {
// 		fn(args...)
// 	}
// }

func NewThreadPool(count int) *ThreadPool {
	t := &ThreadPool{
		tasks:       queue.NewQueue[fn](),
		mu:          sync.Mutex{},
		workerCount: count,
		stop:        false,
	}

	t.cond = sync.NewCond(&t.mu)

	for i := 1; i < count; i++ {
		go t.defaultThreadDeal()
	}

	return t
}

func (t *ThreadPool) defaultThreadDeal() {
	for {
		t.mu.Lock()
		for t.tasks.Empty() && !t.stop {
			t.cond.Wait()
		}

		if t.stop {
			t.mu.Unlock()
			return
		}

		task := t.tasks.Pop()
		t.mu.Unlock()

		reflect.ValueOf(task.callback).Call(task.args)
	}
}

func (t *ThreadPool) Submit(task interface{}, args ...interface{}) {
	t.mu.Lock()
	defer t.mu.Unlock()

	if t.stop {
		return
	}

	refArgs := make([]reflect.Value, len(args))
	for i, arg := range args {
		refArgs[i] = reflect.ValueOf(arg)
	}

	t.tasks.Push(fn{task, refArgs})
	t.cond.Signal()
}

func (t *ThreadPool) Stop() {
	t.mu.Lock()
	defer t.mu.Unlock()

	t.stop = true
	t.cond.Broadcast()
}
